# _*_ coding:utf-8 _*_
# 开发团队: Mavericks
# 开发人员：Maverick·Ming
# 开发IDE： PyCharm
#   项目名：HelloWorld
#   文件名：5.09 闭包.py
# 开发时间：2021/3/25 14:34

# 闭包
# 将函数作为返回值返回，也是一种高阶函数
# 这种高阶函数也成为闭包
# 通过闭包可以创建一些只有当前函数可以访问的变量
# 可以将一些私有数据隐藏到闭包中
def fn():
    # 函数内部再定义一个函数
    a = 10

    def inner():
        print("我是fn2", a)

    # 将内部函数 innner作为返回值返回
    return inner


r = fn()
# print(r)  # 可见返回了一个函数
r()
# r是一个函数，是调用fn后返回的函数
# 这个函数是在fn()内部定义的，并非全局函数
# 所以此函数，总是能访问到fn()内部的变量
# print(a)  # 在全局无法访问局部的变量a，所以就形成了闭包
print(r())  # 只有内部函数inner可以访问到

# 用例：求多个数的平均值
nums = [1, 2, 3, 4]
# sum() 函数用来求和
print(sum(nums) / len(nums))


def make_averager():
    # 创建一个列表，用来保存数值
    nums = []

    # 创建一个函数，用来计算平均值(每次插入一个新值都求一次)
    def averager_fn(n):
        # 将n添加到l列表中
        nums.append(n)
        # 求平均值
        return sum(nums) / len(nums)

    return averager_fn  # 返回闭包里的函数，这样就可以通过此函数访问数据了


averager = make_averager()
print(averager(50))
print(averager(150))
# 如果别人用了同名的nums创建列表,这样就会导致原本的nums被覆盖了，没法用了
# nums = []
# nums.append('hello')
# 为了把这部分隐藏起来，不让别人访问操作，我们可以利用闭包
print(averager(200))


# 形成闭包的条件
#   1.函数嵌套
#   2.将内部函数作为返回值
#   3.内部函数必须要使用到外部函数的变量(子函数用父函数的变量)
